package com.powergisol.core.model;


import com.powergisol.gis.geom.GeoPoint;
import com.powergisol.gis.geom.GeoPolygon;
import com.powergisol.core.math.Dot;
import com.powergisol.core.math.Line;
import com.powergisol.core.math.Plane;
import com.powergisol.core.math.Vector;
import com.vividsolutions.jts.geom.Coordinate;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class VirtualDrillCreater {
    /**
     * 直线的方向向量
     */
    private  double[] drectionVector = new double[]{0,0,5};
    /**
     * 求经过一点的切垂直于地面的直线与任意三角面的交点
     * @param geoPolygon
     * @param point
     * @return
     */
    public GeoPoint getIntersectPoint(GeoPolygon geoPolygon,GeoPoint point){


        Coordinate[] coordinates = geoPolygon.getCoordinates();
        if(coordinates.length!=4){
            throw new RuntimeException("只支撑三角型的运算");
        }

        List<double[]> triangle = new ArrayList<>();

        for (int i = 0; i < coordinates.length; i++) {
            double x = coordinates[i].x;
            double y = coordinates[i].y;
            double z = coordinates[i].z;
            double[] doubles = {x,y,z};
            triangle.add(doubles);
        }


        double[] p0 = point.getPoints();// 直线经过的一点

        double[] p1 = triangle.get(0);
        double[] p2 = triangle.get(1);
        double[] p3 = triangle.get(2);



        double[] normalVector = calNormalVector(p1, p2, p3);
        double[] intersect = calPlaneLineIntersectPoint(normalVector, p1, drectionVector, p0);

        return new GeoPoint(intersect);
    }


    public GeoPoint getIntersectPointByMath(GeoPolygon geoPolygon,GeoPoint point){

        Plane plane = geoPolygon.toPlane();
        Dot dot = point.toDot();
        Vector vector = new Vector(0,0,5);

        Line line = new Line(dot,vector);
        Dot intersection = plane.getIntersection(line);

        GeoPoint geoPoint = new GeoPoint(intersection.getX(),intersection.getY(),intersection.getZ());

        return geoPoint;
    }

    /**
     * 求平面和直线的交点
     * @param planeVector 平面的法线向量，长度为3
     * @param planePoint 平面经过的一点坐标
     * @param lineVector 直线的方向向量
     * @param linePoint 直线经过的一点坐标
     * @return
     */
    public double[] calPlaneLineIntersectPoint(double[] planeVector, double[] planePoint, double[] lineVector, double[] linePoint) {
        double[] returnResult = new double[3];
        double vp1, vp2, vp3, n1, n2, n3, v1, v2, v3, m1, m2, m3, t,vpt;
        vp1 = planeVector[0];
        vp2 = planeVector[1];
        vp3 = planeVector[2];
        n1 = planePoint[0];
        n2 = planePoint[1];
        n3 = planePoint[2];
        v1 = lineVector[0];
        v2 = lineVector[1];
        v3 = lineVector[2];
        m1 = linePoint[0];
        m2 = linePoint[1];
        m3 = linePoint[2];
        vpt = v1 * vp1 + v2 * vp2 + v3 * vp3;
        //首先判断直线是否与平面平行
        if (vpt == 0) {
            returnResult = null;
        }
        else {
            t = ((n1 - m1) * vp1 + (n2 - m2) * vp2 + (n3 - m3) * vp3) / vpt;
            returnResult[0] = m1 + v1 * t;
            returnResult[1] = m2 + v2 * t;
            returnResult[2] = m3 + v3 * t;
        }
        return returnResult;
    }

    /**
     * 求三点形成的面的法向量 https://blog.csdn.net/sinat_41104353/article/details/84963016
     * @param v0
     * @param v1
     * @param v2
     * @return
     */
    private double[] calNormalVector(double[] v0,double[] v1,double[] v2){
        double x1=v0[0],y1=v0[1],z1=v0[2],x2=v1[0],y2=v1[1],z2=v1[2],x3=v2[0],y3=v2[1],z3=v2[2];
        int dx=0,dy=0,dz=0;

        double _a1=x2-x1; double _b1=y2-y1; double _c1=z2-z1;
        double _a2=x3-x1; double _b2=y3-y1; double _c2=z3-z1;
        double _a3=x3-x2; double _b3=y3-y2; double _c3=z3-z2;

        double da=_a1*_b2*_c3+_b1*_c2*_a3+_a2*_b3*_c1-_a3*_b2*_c1-_a1*_b3*_c2-_a2*_b1*_c3;

        if (da!=0) {
            dx=0;
            dy=0;
            dz=0;
        }

        //---------------------------------------------//
        //如果行列式A的值等于0，则有非零解
        //非零解即x!=0时有解或者y!=0时有解或者z!=0时有解
        int x=0,y=0,z=0;

        boolean flag3=getTwoLineIntersection(_a1,_b1,_c1,_a2,_b2,_c2,x,y);

        if (flag3)//假设成立
        {
            dx=-x;
            dy=-y;
            dz=1;
            return new double[]{dx,dy,dz};
        }

        y=0;z=0;
        boolean flag1=getTwoLineIntersection(_b1,_c1,_a1,_b2,_c2,_a2,y,z);
        //假设成立
        if (flag1) {
            dx=1;
            dy=-y;
            dz=-z;
            return new double[]{dx,dy,dz};
        }

        x=0;z=0;
        boolean flag2=getTwoLineIntersection(_a1,_c1,_b1,_a2,_c2,_b2,x,z);
        if (flag2)//假设成立
        {
            dx=-x;
            dy=1;
            dz=-z;
            return new double[]{dx,dy,dz};
        }
        //所有假设都不成立，求解失败
        return new double[]{dx,dy,dz};
    }

    private boolean getTwoLineIntersection(double _a1,double _b1,double _c1,double _a2,double _b2,double _c2,double x, double y){
        if (_c1==0&&_c2==0) {
            //2个未知数2个方程组成的齐次方程组求解
            //系数矩阵B
            //| _a1 _b1 |
            //| _a2 _b2 |
            double DB=_a1*_b2-_a2*_b1;
            //有唯一零解
            if (DB!=0){
                x=0;
                y=0;
                return true;
            }
            // 有无数解
            else{
                x=0;
                y=0;
                return false;
            }
        }else{
            //2个未知数2个方程组成的非齐次方程组求解
            //系数矩阵B
            //| _a1 _b1 |
            //| _a2 _b2 |
            //
            double DB=_a1*_b2-_a2*_b1;
            //有唯一解
            if (DB!=0) {
                double dD1 = _c1 * _b2 - _c2 * _b1;
                double dD2 = _a1 * _c2 - _a2 * _c1;
                x = dD1 / DB;
                y= dD2 / DB;
                return true;
            }
            //有无数解或者无解
            else {
                x=0;
                y=0;
                return false;
            }
        }
    }

    public static void main(String[] args) {


        double[] p1 = new double[]{92.05782,29.791265,0};
        double[] p2 = new double[]{91.905132,29.286605,0};
        double[] p3 = new double[]{92.58759,29.496853,0};
        double[] p = new double[]{92.129007,29.581417,0};
        double[] p0 = new double[]{91.640804,29.306686,0};

        double[] pp = new double[]{0,0,5};

        VirtualDrillCreater creater = new VirtualDrillCreater();
        double[] doubles = creater.calNormalVector(p1, p2, p3);

        System.out.println(Arrays.toString(doubles));
        //double[] doubles1 = calPlaneLineIntersectPoint(doubles, p1, pp, p0);
        //System.out.println(doubles1[0]+","+doubles1[1]+","+doubles1[2]);

    }

}
